SAM Pipelineで作成されるリソースを眺めてみる
「実際に手を動かす前に、SAM Pipelineの雰囲気をなんとなく掴みたい。。」
SAM Pipelineは対話形式で必要な情報を渡すと、サーバレスアプリケーションのデプロイパイプライン用のCloudFormation Templateを自動生成してくれます。
パイプライン作成をよしなにやってくれる機能ではありますが、中身もある程度知っておきたいものです。
勉強がてら作成してくれるリソースを眺めてみます。
準備: SAM Pipelineの作成
CodeCommitをソースにして、PipelineはCodePipelineを使用したものを作成します。
コマンドを実行して、CloudFormation Template等必要なファイルを用意します。
SAM Pipelineの使い方やデプロイの流れは以下の記事がわかりやすかったです。
% sam pipeline bootstrap # 省略 [4] Summary Below is the summary of the answers: 1 - Account: 0000000 2 - Stage configuration name: dev 3 - Region: ap-northeast-1 4 - Pipeline user: [to be created] 5 - Pipeline execution role: [to be created] 6 - CloudFormation execution role: [to be created] 7 - Artifacts bucket: [to be created] 8 - ECR image repository: [skipped]
% sam pipeline init # 省略 SUMMARY We will generate a pipeline config file based on the following information: What is the Git provider?: CodeCommit What is the CodeCommit repository name?: samp-app-test What is the Git branch used for production deployments?: main What is the template file path?: template.yaml Select an index or enter the stage 1's configuration name (as provided during the bootstrapping): sam-app-dev What is the sam application stack name for stage 1?: sam-app-prd What is the pipeline execution role ARN for stage 1?: arn:aws:iam::000000000:role/aws-sam-cli-managed-dev-pipe-PipelineExecutionRole-QO6TWPN0NBLJ What is the CloudFormation execution role ARN for stage 1?: arn:aws:iam::000000000:role/aws-sam-cli-managed-dev-p-CloudFormationExecutionR-7KYS28POR6G8 What is the S3 bucket name for artifacts for stage 1?: aws-sam-cli-managed-dev-pipeline-artifactsbucket-ywqrfhm83rhl What is the ECR repository URI for stage 1?: What is the AWS region for stage 1?: ap-northeast-1 Select an index or enter the stage 2's configuration name (as provided during the bootstrapping): 1 What is the sam application stack name for stage 2?: sam-app What is the pipeline execution role ARN for stage 2?: arn:aws:iam::000000000:role/aws-sam-cli-managed-dev-pipe-PipelineExecutionRole-QO6TWPN0NBLJ What is the CloudFormation execution role ARN for stage 2?: arn:aws:iam::000000000:role/aws-sam-cli-managed-dev-p-CloudFormationExecutionR-7KYS28POR6G8 What is the S3 bucket name for artifacts for stage 2?: aws-sam-cli-managed-dev-pipeline-artifact What is the ECR repository URI for stage 2?: What is the AWS region for stage 2?: ap-northeast-1
上記コマンドを実行すると、以下のようにファイルが作成されます。
├── ./assume-role.sh ├── ./codepipeline.yaml └── ./pipeline ├── ./pipeline/buildspec_build_package.yml ├── ./pipeline/buildspec_deploy.yml ├── ./pipeline/buildspec_feature.yml ├── ./pipeline/buildspec_integration_test.yml └── ./pipeline/buildspec_unit_test.yml
初期生成される雛形ファイルの中身は、Githubからも確認できます。
Github aws/aws-sam-cli-pipeline-init-templates
眺めてみる
CloudFormatoin Tempalte(codepipeline.yaml)
まずは、CloudFormation Templateであるcodepipeline.yamlです。
codepipeline.yaml
AWSTemplateFormatVersion : '2010-09-09' Description: > This template deploys a CodePipeline with its required resources. The following stages are predefined in this template: - Source - UpdatePipeline - BuildAndDeployFeatureStack (FeatureGitBranch only) - BuildAndPackage (MainGitBranch only) - DeployTest (MainGitBranch only) - DeployProd (MainGitBranch only) **WARNING** You will be billed for the AWS resources used if you create a stack from this template. # To deploy this template and connect to the main git branch, run this against the leading account: # `sam deploy -t codepipeline.yaml --stack-name <stack-name> --capabilities=CAPABILITY_IAM`. # If later you need to deploy a new CodePipeline to connect to a non-main git branch, run # # sam deploy -t codepipeline.yaml --stack-name <stack-name> --capabilities=CAPABILITY_IAM \ # --parameter-overrides="FeatureGitBranch=<branch-name>" # Parameters: GitProviderType: Type: String Default: "CodeCommit" CodeCommitRepositoryName: Type: String Default: "samp-app-test" MainGitBranch: Type: String Default: "main" SamTemplate: Type: String Default: "template.yaml" TestingRegion: Type: String Default: "ap-northeast-1" TestingStackName: Type: String Default: "sam-app-prd" TestingPipelineExecutionRole: Type: String Default: "arn:aws:iam::00000000000:role/aws-sam-cli-managed-dev-pipe-PipelineExecutionRole-QO6TWPN0NBLJ" TestingCloudFormationExecutionRole: Type: String Default: "arn:aws:iam::00000000000:role/aws-sam-cli-managed-dev-p-CloudFormationExecutionR-7KYS28POR6G8" TestingArtifactBucket: Type: String Default: "bucket" TestingImageRepository: Type: String # If there are functions with "Image" PackageType in your template, # Update the line below with image repository URL and add "--image-repository ${TESTING_IMAGE_REPOSITORY}" to # prod "sam package" and "sam deploy" commands in buildspec files (in pipeline/). Default: "" ProdRegion: Type: String Default: "ap-northeast-1" ProdStackName: Type: String Default: "sam-app" ProdPipelineExecutionRole: Type: String Default: "arn:aws:iam::00000000000:role/aws-sam-cli-managed-dev-pipe-PipelineExecutionRole-QO6TWPN0NBLJ" ProdCloudFormationExecutionExeRole: Type: String Default: "arn:aws:iam::00000000000:role/aws-sam-cli-managed-dev-p-CloudFormationExecutionR-7KYS28POR6G8" ProdArtifactBucket: Type: String Default: "bucket" ProdImageRepository: Type: String # If there are functions with "Image" PackageType in your template, # Update the line below with image repository URL and add "--image-repository ${PROD_IMAGE_REPOSITORY}" to # prod "sam package" and "sam deploy" commands in buildspec files (in pipeline/). Default: "" # CodeStarConnectionArn and FeatureGitBranch are required for pipelines for feature branches CodeStarConnectionArn: Type: String Default: "" FeatureGitBranch: Type: String Default: "" Conditions: IsMainBranchPipeline: !Equals [!Ref FeatureGitBranch, ""] IsFeatureBranchPipeline: !Not [Condition: IsMainBranchPipeline] Resources: # ____ # / ___| ___ _ _ _ __ ___ ___ # \___ \ / _ \| | | | '__/ __/ _ \ # ___) | (_) | |_| | | | (_| __/ # |____/ \___/ \__,_|_| \___\___| CloudWatchEventRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: cwe-pipeline-execution PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: codepipeline:StartPipelineExecution Resource: !Sub "arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}" CloudWatchEventRule: Type: AWS::Events::Rule Properties: EventPattern: source: - aws.codecommit detail-type: - 'CodeCommit Repository State Change' resources: - !Sub "arn:${AWS::Partition}:codecommit:${AWS::Region}:${AWS::AccountId}:${CodeCommitRepositoryName}" detail: event: - referenceCreated - referenceUpdated referenceType: - branch referenceName: - !If [IsFeatureBranchPipeline, !Ref FeatureGitBranch, !Ref MainGitBranch] Targets: - Arn: !Sub "arn:${AWS::Partition}:codepipeline:${AWS::Region}:${AWS::AccountId}:${Pipeline}" RoleArn: !GetAtt CloudWatchEventRole.Arn Id: codepipeline-AppPipeline # ____ _ _ _ # | _ \(_)_ __ ___| (_)_ __ ___ # | |_) | | '_ \ / _ | | | '_ \ / _ \ # | __/| | |_) | __| | | | | | __/ # |_| |_| .__/ \___|_|_|_| |_|\___| # |_| Pipeline: Type: AWS::CodePipeline::Pipeline Properties: ArtifactStore: Location: !Ref PipelineArtifactsBucket Type: S3 RoleArn: !GetAtt CodePipelineExecutionRole.Arn RestartExecutionOnUpdate: true Stages: - Name: Source Actions: - Name: SourceCodeRepo ActionTypeId: Category: Source Owner: AWS Provider: CodeCommit Version: "1" Configuration: RepositoryName: !Ref CodeCommitRepositoryName PollForSourceChanges: false BranchName: !If [IsFeatureBranchPipeline, !Ref FeatureGitBranch, !Ref MainGitBranch] OutputArtifacts: - Name: SourceCodeAsZip RunOrder: 1 - Name: UpdatePipeline Actions: - Name: CreateChangeSet ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: ActionMode: CHANGE_SET_REPLACE RoleArn: !GetAtt PipelineStackCloudFormationExecutionRole.Arn StackName: !Ref AWS::StackName ChangeSetName: !Sub ${AWS::StackName}-ChangeSet TemplatePath: SourceCodeAsZip::codepipeline.yaml Capabilities: CAPABILITY_NAMED_IAM ParameterOverrides: !Sub | { "FeatureGitBranch": "${FeatureGitBranch}", "CodeStarConnectionArn": "${CodeStarConnectionArn}" } InputArtifacts: - Name: SourceCodeAsZip RunOrder: 1 - Name: ExecuteChangeSet ActionTypeId: Category: Deploy Owner: AWS Provider: CloudFormation Version: "1" Configuration: ActionMode: CHANGE_SET_EXECUTE RoleArn: !GetAtt PipelineStackCloudFormationExecutionRole.Arn StackName: !Ref AWS::StackName ChangeSetName: !Sub ${AWS::StackName}-ChangeSet OutputArtifacts: - Name: !Sub ${AWS::StackName}ChangeSet RunOrder: 2 # Uncomment and modify the following step for running the unit-tests # - Name: UnitTest # Actions: # - Name: UnitTest # ActionTypeId: # Category: Build # Owner: AWS # Provider: CodeBuild # Version: "1" # Configuration: # ProjectName: !Ref CodeBuildProjectUnitTest # InputArtifacts: # - Name: SourceCodeAsZip - !If - IsFeatureBranchPipeline - Name: BuildAndDeployFeatureStack Actions: - Name: CodeBuild ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: !Ref CodeBuildProjectBuildAndDeployFeature InputArtifacts: - Name: SourceCodeAsZip - !Ref AWS::NoValue - !If - IsMainBranchPipeline - Name: BuildAndPackage Actions: - Name: CodeBuild ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: !Ref CodeBuildProjectBuildAndPackage InputArtifacts: - Name: SourceCodeAsZip OutputArtifacts: - Name: BuildArtifactAsZip - !Ref AWS::NoValue - !If - IsMainBranchPipeline - Name: DeployTest Actions: - Name: DeployTest ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" Configuration: ProjectName: !Ref CodeBuildProjectDeploy EnvironmentVariables: !Sub | [ {"name": "ENV_TEMPLATE", "value": "packaged-test.yaml"}, {"name": "ENV_REGION", "value": "${TestingRegion}"}, {"name": "ENV_STACK_NAME", "value": "${TestingStackName}"}, {"name": "ENV_PIPELINE_EXECUTION_ROLE", "value": "${TestingPipelineExecutionRole}"}, {"name": "ENV_CLOUDFORMATION_EXECUTION_ROLE", "value": "${TestingCloudFormationExecutionRole}"}, {"name": "ENV_BUCKET", "value": "${TestingArtifactBucket}"}, {"name": "ENV_IMAGE_REPOSITORY", "value": "${TestingImageRepository}"} ] InputArtifacts: - Name: BuildArtifactAsZip RunOrder: 1 # Uncomment the following step for running the integration tests # - Name: IntegrationTest # ActionTypeId: # Category: Build # Owner: AWS # Provider: CodeBuild # Version: "1" # Configuration: # ProjectName: !Ref CodeBuildProjectIntegrationTest # InputArtifacts: # - Name: SourceCodeAsZip # RunOrder: 2 - !Ref AWS::NoValue - !If - IsMainBranchPipeline - Name: DeployProd Actions: # uncomment this to have a manual approval step before deployment to production # - Name: ManualApproval # ActionTypeId: # Category: Approval # Owner: AWS # Provider: Manual # Version: "1" # RunOrder: 1 - Name: DeployProd ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: "1" RunOrder: 2 # keeping run order as 2 in case manual approval is enabled Configuration: ProjectName: !Ref CodeBuildProjectDeploy EnvironmentVariables: !Sub | [ {"name": "ENV_TEMPLATE", "value": "packaged-prod.yaml"}, {"name": "ENV_REGION", "value": "${ProdRegion}"}, {"name": "ENV_STACK_NAME", "value": "${ProdStackName}"}, {"name": "ENV_PIPELINE_EXECUTION_ROLE", "value": "${ProdPipelineExecutionRole}"}, {"name": "ENV_CLOUDFORMATION_EXECUTION_ROLE", "value": "${ProdCloudFormationExecutionExeRole}"}, {"name": "ENV_BUCKET", "value": "${ProdArtifactBucket}"}, {"name": "ENV_IMAGE_REPOSITORY", "value": "${ProdImageRepository}"} ] InputArtifacts: - Name: BuildArtifactAsZip - !Ref AWS::NoValue PipelineArtifactsBucket: Type: AWS::S3::Bucket DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: VersioningConfiguration: Status: Enabled LoggingConfiguration: DestinationBucketName: !Ref PipelineArtifactsLoggingBucket LogFilePrefix: "artifacts-logs" BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 PipelineArtifactsBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref PipelineArtifactsBucket PolicyDocument: Statement: - Effect: "Deny" Action: "s3:*" Principal: "*" Resource: - !Sub "${PipelineArtifactsBucket.Arn}/*" - !GetAtt PipelineArtifactsBucket.Arn Condition: Bool: aws:SecureTransport: false - Action: - s3:* Effect: Allow Resource: - !Sub arn:${AWS::Partition}:s3:::${PipelineArtifactsBucket} - !Sub arn:${AWS::Partition}:s3:::${PipelineArtifactsBucket}/* Principal: AWS: - !GetAtt CodePipelineExecutionRole.Arn PipelineArtifactsLoggingBucket: Type: AWS::S3::Bucket DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: AccessControl: "LogDeliveryWrite" VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 PipelineArtifactsLoggingBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref PipelineArtifactsLoggingBucket PolicyDocument: Statement: - Effect: "Deny" Action: "s3:*" Principal: "*" Resource: - !Sub "${PipelineArtifactsLoggingBucket.Arn}/*" - !GetAtt PipelineArtifactsLoggingBucket.Arn Condition: Bool: aws:SecureTransport: false CodePipelineExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Action: - "sts:AssumeRole" Effect: Allow Principal: Service: - codepipeline.amazonaws.com Policies: - PolicyName: CodePipelineAccess PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "iam:PassRole" Resource: "*" - PolicyName: CodeCommitAccess PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'codecommit:CancelUploadArchive' - 'codecommit:GetBranch' - 'codecommit:GetCommit' - 'codecommit:GetUploadArchiveStatus' - 'codecommit:UploadArchive' Resource: - !Sub "arn:${AWS::Partition}:codecommit:${AWS::Region}:${AWS::AccountId}:${CodeCommitRepositoryName}" - PolicyName: CodePipelineCodeAndS3Bucket PolicyDocument: Version: "2012-10-17" Statement: - Action: - s3:GetBucketAcl - s3:GetBucketLocation Effect: Allow Resource: Fn::GetAtt: - PipelineArtifactsBucket - Arn - Action: - "s3:GetObject" - "s3:GetObjectVersion" - "s3:PutObject" Effect: Allow Resource: Fn::Sub: ${PipelineArtifactsBucket.Arn}/* - PolicyName: CodePipelineCodeBuildAndCloudformationAccess PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "codebuild:StartBuild" - "codebuild:BatchGetBuilds" Resource: # Uncomment the line below to enable the unit-tests # - !GetAtt CodeBuildProjectUnitTest.Arn - !If - IsFeatureBranchPipeline - !GetAtt CodeBuildProjectBuildAndDeployFeature.Arn - !Ref AWS::NoValue - !If - IsMainBranchPipeline - !GetAtt CodeBuildProjectBuildAndPackage.Arn - !Ref AWS::NoValue # Uncomment the following step for running the integration tests # - !If # - IsMainBranchPipeline # - !GetAtt CodeBuildProjectIntegrationTest.Arn # - !Ref AWS::NoValue - !If - IsMainBranchPipeline - !GetAtt CodeBuildProjectDeploy.Arn - !Ref AWS::NoValue - Effect: Allow Action: - "cloudformation:CreateStack" - "cloudformation:DescribeStacks" - "cloudformation:DeleteStack" - "cloudformation:UpdateStack" - "cloudformation:CreateChangeSet" - "cloudformation:ExecuteChangeSet" - "cloudformation:DeleteChangeSet" - "cloudformation:DescribeChangeSet" - "cloudformation:SetStackPolicy" - "cloudformation:SetStackPolicy" - "cloudformation:ValidateTemplate" Resource: - !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}/*" # PipelineStackCloudFormationExecutionRole is used for the pipeline to self mutate PipelineStackCloudFormationExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: Action: "sts:AssumeRole" Effect: Allow Principal: Service: cloudformation.amazonaws.com Policies: - PolicyName: GrantCloudFormationFullAccess PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: '*' Resource: '*' # ____ _ ____ _ _ _ # / ___|___ __| | ___| __ ) _ _(_| | __| | # | | / _ \ / _` |/ _ | _ \| | | | | |/ _` | # | |__| (_) | (_| | __| |_) | |_| | | | (_| | # \____\___/ \__,_|\___|____/ \__,_|_|_|\__,_| CodeBuildServiceRole: Type: AWS::IAM::Role Properties: Tags: - Key: Role Value: aws-sam-pipeline-codebuild-service-role AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Action: - "sts:AssumeRole" Effect: Allow Principal: Service: - codebuild.amazonaws.com Policies: - PolicyName: CodeBuildLogs PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: - !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*" - PolicyName: CodeBuildArtifactsBucket PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "s3:GetObject" - "s3:GetObjectVersion" - "s3:PutObject" Resource: - !Sub "arn:${AWS::Partition}:s3:::${PipelineArtifactsBucket}/*" - PolicyName: AssumeStagePipExecutionRoles PolicyDocument: Version: "2012-10-17" Statement: - Action: - sts:AssumeRole Effect: Allow Resource: "*" Condition: StringEquals: aws:ResourceTag/Role: pipeline-execution-role # Uncomment and modify the following step for running the unit-tests # CodeBuildProjectUnitTest: # Type: AWS::CodeBuild::Project # Properties: # Artifacts: # Type: CODEPIPELINE # Environment: # Type: LINUX_CONTAINER # ComputeType: BUILD_GENERAL1_SMALL # Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 # ServiceRole: !GetAtt CodeBuildServiceRole.Arn # Source: # Type: CODEPIPELINE # BuildSpec: pipeline/buildspec_unit_test.yml CodeBuildProjectBuildAndDeployFeature: Condition: IsFeatureBranchPipeline Type: AWS::CodeBuild::Project Properties: Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 PrivilegedMode: true EnvironmentVariables: - Name: SAM_TEMPLATE Value: !Ref SamTemplate - Name: TESTING_REGION Value: !Ref TestingRegion - Name: TESTING_PIPELINE_EXECUTION_ROLE Value: !Ref TestingPipelineExecutionRole - Name: TESTING_CLOUDFORMATION_EXECUTION_ROLE Value: !Ref TestingCloudFormationExecutionRole - Name: TESTING_ARTIFACT_BUCKET Value: !Ref TestingArtifactBucket - Name: TESTING_IMAGE_REPOSITORY Value: !Ref TestingImageRepository - Name: FEATURE_BRANCH_NAME Value: !Ref FeatureGitBranch ServiceRole: !GetAtt CodeBuildServiceRole.Arn Source: Type: CODEPIPELINE BuildSpec: pipeline/buildspec_feature.yml CodeBuildProjectBuildAndPackage: Condition: IsMainBranchPipeline Type: AWS::CodeBuild::Project Properties: Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 PrivilegedMode: true EnvironmentVariables: - Name: SAM_TEMPLATE Value: !Ref SamTemplate - Name: TESTING_REGION Value: !Ref TestingRegion - Name: PROD_REGION Value: !Ref ProdRegion - Name: TESTING_PIPELINE_EXECUTION_ROLE Value: !Ref TestingPipelineExecutionRole - Name: PROD_PIPELINE_EXECUTION_ROLE Value: !Ref ProdPipelineExecutionRole - Name: TESTING_ARTIFACT_BUCKET Value: !Ref TestingArtifactBucket - Name: PROD_ARTIFACT_BUCKET Value: !Ref ProdArtifactBucket - Name: TESTING_IMAGE_REPOSITORY Value: !Ref TestingImageRepository - Name: PROD_IMAGE_REPOSITORY Value: !Ref ProdImageRepository ServiceRole: !GetAtt CodeBuildServiceRole.Arn Source: Type: CODEPIPELINE BuildSpec: pipeline/buildspec_build_package.yml # Uncomment and modify the following step for running the integration tests # CodeBuildProjectIntegrationTest: # Condition: IsMainBranchPipeline # Type: AWS::CodeBuild::Project # Properties: # Artifacts: # Type: CODEPIPELINE # Environment: # Type: LINUX_CONTAINER # ComputeType: BUILD_GENERAL1_SMALL # Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 # ServiceRole: !GetAtt CodeBuildServiceRole.Arn # Source: # Type: CODEPIPELINE # BuildSpec: pipeline/buildspec_integration_test.yml CodeBuildProjectDeploy: Condition: IsMainBranchPipeline Type: AWS::CodeBuild::Project Properties: Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0 ServiceRole: !GetAtt CodeBuildServiceRole.Arn Source: Type: CODEPIPELINE BuildSpec: pipeline/buildspec_deploy.yml
AWS CloudFormation Designer では以下のように表示されました。
このCFnに含まれているリソースは以下になります。
- CodePipeline * 1
- Cloudwatch Event * 1
- S3 Bucket/BucketPolicy * 2
- CodeBuildProject * 3
- IAM Role * 4
デプロイパイプライン用のCodePipelineと、CodeCommitの変更をトリガーにCodePipelineを発火させるための CloudwatchEventが1つずつ作成されます。
S3 Bucketはsamのartifact保存用バケットと、そのバケットのロギング用のバケットが作成されています。
今回の設定では、CodeBuildは3つ作成されました。
- featureブランチのビルド・デプロイ
- mainブランチのビルド・パッケージ
- mainブランチのデプロイ
unit testやintegretion test用のbuildspecのファイルは作成されていますが、CloudFormation上ではコメントアウトされています。
IAMロールは、4つ作成されます。
- CloudwatchEvent
- CodePipelineのスタート - CodeCommitの変更を検知してCodePipelineを発火させる
- CodePipeline
- CodeCommitへのアクセス
- Artifact Bucketの読み書き
- CodeBuild実行
- CodeBuild
- Artifact Bucketの読み書き
- CloudwatchLogsへのログ出力
- sam deploy用のIAMロールの引き受け(assume-role)
- Cloudformation
- CloudFormationのフルアクセス
- sam deployでCloudformationを実行するIAMロールを指定
buildspec(pipeline配下)
pipeline ├── pipeline/buildspec_build_package.yml ├── pipeline/buildspec_deploy.yml ├── pipeline/buildspec_feature.yml # 今回は使用しない ├── pipeline/buildspec_integration_test.yml # デフォルトでは使用するCodeBuildがコメントアウトされている └── pipeline/buildspec_unit_test.yml # デフォルトでは使用するCodeBuildがコメントアウトされている
今回は、デフォルトで無効化されている buildspec_integration_test.yml と buildspec_unit_test.yml の説明は省きます。 (testの部分は初期ではechoしているだけなので、ユーザー自身で編集する必要があります。)
同じく、buildspec_feature.yml も説明を省きます。 Featureブランチをトリガーにしたデプロイ設定する場合、今回はmainブランチだけをデプロイのトリガーにしています。
上記リンクのGithub上の雛形からも内容を確認できます。
ステージ「BuildAndPackage」では、sam buildとsam pacakgeコマンドを実行してデプロイに必要なパッケージの用意をしています。 本番とテストどちらも一つのビルドプロジェクトで作成しています。
buildspec_build_package.yml
version: 0.2 phases: install: runtime-versions: python: 3.8 commands: - pip install --upgrade pip - pip install --upgrade awscli aws-sam-cli # Enable docker https://docs.aws.amazon.com/codebuild/latest/userguide/sample-docker-custom-image.html - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2 & - timeout 15 sh -c "until docker info; do echo .; sleep 1; done" build: commands: - sam build --use-container --template ${SAM_TEMPLATE} - . ./assume-role.sh ${TESTING_PIPELINE_EXECUTION_ROLE} test-package - sam package --s3-bucket ${TESTING_ARTIFACT_BUCKET} --region ${TESTING_REGION} --output-template-file packaged-test.yaml - . ./assume-role.sh ${PROD_PIPELINE_EXECUTION_ROLE} prod-package - sam package --s3-bucket ${PROD_ARTIFACT_BUCKET} --region ${PROD_REGION} --output-template-file packaged-prod.yaml artifacts: files: - packaged-test.yaml - packaged-prod.yaml - assume-role.sh - pipeline/*
ステージ「DeployTest」「DeployProd」では、前のステージで作成したパッケージを使用してsam deployを実行しています。 CodePipeline側で環境変数を渡して、本番とテストの環境差異(スタック名や、template)を表現しています。
buildspec_deploy.yml
version: 0.2 phases: install: runtime-versions: python: 3.8 commands: - pip install --upgrade pip - pip install --upgrade awscli aws-sam-cli build: commands: - . ./assume-role.sh ${ENV_PIPELINE_EXECUTION_ROLE} deploy - sam deploy --stack-name ${ENV_STACK_NAME} --template ${ENV_TEMPLATE} --capabilities CAPABILITY_IAM --region ${ENV_REGION} --s3-bucket ${ENV_BUCKET} --no-fail-on-empty-changeset --role-arn ${ENV_CLOUDFORMATION_EXECUTION_ROLE}
assume-role.shとIAMロール
buildspec上でたびたび出てきた、assume-role.sh についてです。
その名の通り、ロールを引き受けて一時的に発行されるIAMアクセスキー等をセットするスクリプトです。
#!/bin/bash ROLE=$1 SESSION_NAME=$2 # Unset AWS credentials stored in env so that every time this script runs, # it will use the AWS CodeBuild service role to assume the target IAM roles. unset AWS_SESSION_TOKEN unset AWS_ACCESS_KEY_ID unset AWS_SECRET_ACCESS_KEY cred=$(aws sts assume-role --role-arn "$ROLE" \ --role-session-name "$SESSION_NAME" \ --query '[Credentials.AccessKeyId,Credentials.SecretAccessKey,Credentials.SessionToken]' \ --output text) ACCESS_KEY_ID=$(echo "$cred" | awk '{ print $1 }') export AWS_ACCESS_KEY_ID=$ACCESS_KEY_ID SECRET_ACCESS_KEY=$(echo "$cred" | awk '{ print $2 }') export AWS_SECRET_ACCESS_KEY=$SECRET_ACCESS_KEY SESSION_TOKEN=$(echo "$cred" | awk '{ print $3 }') export AWS_SESSION_TOKEN=$SESSION_TOKEN
作成されるCodeBuildには、共通のIAMロールがついています。 このIAMロール自体には、CloudFormationを更新することができる権限はついていません。
sam deployにはCloudFormationを更新する権限が必要です。
ステージ:BuildAndPackage/DeployTest/DeployProdのCodeBuildで、それぞれCloudFormationとS3を操作可能なIAMロールを引き受けています。
CodeBuildServiceRole ポリシー
{ "Version": "2012-10-17", "Statement": [ { "Condition": { "StringEquals": { "aws:ResourceTag/Role": "pipeline-execution-role" } }, "Action": [ "sts:AssumeRole" ], "Resource": "*", "Effect": "Allow" } ] }
PipelineExecutionRole 信頼関係
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::00000000:user/aws-sam-cli-managed-dev-pipeline-reso-PipelineUser-1H2HRIQ8A3JGV" }, "Action": "sts:AssumeRole" }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::00000000:root" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "aws:PrincipalTag/Role": "aws-sam-pipeline-codebuild-service-role" } } } ] }
おわりに
SAM Pipelineで作成されるリソースについてでした。
ちなみに、sam pipeline init時のプロンプトをカスタマイズすることができるそうです。 利用頻度が多い場合は、この機能を使ってテンプレートを作成するのもいいかもしれません。
スターターパイプラインのカスタマイズ - AWS Serverless Application Model
この記事が、SAM Pipelineの雰囲気を掴むのに役立てば幸いです。
以上、AWS事業本部の佐藤(@chari7311)でした。